CloudWatch Eventsのルールで日本時刻の月末(0時~9時)が指定できない時の対処法
困っていたこと
「日本時間(JST)の毎月末の午前5:00に処理を実行する」というCloudWatchのEventsルールをCron式で設定することは可能でしょうか?
月末という指定があるため、CloudWatch Eventsルールのワイルドカードを使用して設定しようと考えておりますが、UTC時刻が基準のため月末を指定したときに午前5:00を指定できない認識です。
月末の0時から9時は月末を指定するワイルドカード(L)を使用する必要がありますが、それではUTCの時刻の月末となってしまいます。
そのため、JSTとの時差を考慮してUTCである9時間前を指定しようとすると、月末1日前という指定になってしまうため、月末のワイルドカードが使用できません。
どう対応すればいいの?
今回の場合、「日本時間(JST)の毎月末の午前5:00に処理を実行する」必要があるため、月末1日前の20時に発火するCloudWatch Eventsルールを作成する必要があります。
しかし、CloudWatch EventsルールのCron式で使えるものに月末1日前を指定できるものはないため、CloudWatch Eventsの機能のみでは実装はできません。
そのため、CloudWatch Events をトリガーとして Lambda 関数を経由して行いたい処理を実行する方法が考えられます。
今回の場合は以下の条件でCloudWatch EventsとLambdaを作成する必要があります。
- CloudWatch Events の Cron 式には 28 - 31 日の 20:00 UTC (JSTで翌日の5:00 )に起動するように設定する
- CloudWatch Events のターゲットとして Lambda 関数を設定いただき、Lambda 関数内で月末の判定を行う
- Lambda 関数による判定の結果、月末である場合に処理を実行する
やってみた
Lambda関数の作成
今回は実行日時を取得して、その日時が月末であるかどうかを判定する必要があります。
サンプルですがpython3.7で以下のようなLambda関数を作成してみました。あくまでサンプルなので、細かい部分はいい感じに編集してください。
実行日の日付とその月の月末を取得し、実行日が月末と同じ日だった場合に処理を実行します。
from datetime import datetime, timedelta, timezone,date from dateutil.relativedelta import relativedelta def is_first_day(): isFirstDay = False JST = timezone(timedelta(hours=+9), 'JST') # 日本時刻で今日の日付を取得 todayJST=datetime.now(JST).date() # その月の月末日付を取得 lastDay = (todayJST + relativedelta(months=1)).replace(day=1) - timedelta(days=1) if todayJST == lastDay : isFirstDay = True return isFirstDay def lambda_handler(event, context): isFirstDay = is_first_day() if isFirstDay == True : # 月末に行いたい処理を書く print('今日は月末です') else: print('今日は月末ではありません')
print
で文字列を出力している部分は、適宜実行したい処理や返したいメッセージに書き換えてください。
CloudWatch Eventsのルール作成
Cron式で28日から31日の20:00 UTC を指定するため、以下をスケジュールに設定します。
0 20 28-31 * ? *
ターゲットには先ほど作成したLambda関数を指定しましょう。
設定の詳細からルールの名前と説明を入力して作成すれば設定は完了です。
これで「日本時間(JST)の毎月末の午前5:00に処理を実行する」ことができるようになりました。